// ==================================================================================
// Shared Genomics Project MPI Codebase
// Version 1.0 30/04/2010
//
// (c) 2010 University of Manchester all rights reserved
//
// This file is distributed under the GNU General Public License, Version 2.  
// Please see the file COPYING.txt for more details
// ==================================================================================

/*!
\file
\brief Implementation of SNP Definition (PLINK)
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "locus.h"

// This is a test.
int locus_init(struct locus *loc) {
	if (loc != NULL) {
		loc->chr = 0; 
		loc->name = '\0'; 
		loc->allele1[0] = '\0'; 
		loc->allele2[0] = '\0';  
		loc->freq = 0; 
		loc->pos = 0; 
		loc->bp = 0; 
		loc->nm = 0;

		// Variant specific fields.
		loc->isVariant = FALSE;
		loc->nAlleles = 0;
		loc->alleles = NULL;
		loc->freqs = NULL;
		loc->nFreqs = 0;
		loc->acode_map_keys = NULL;
		loc->acode_map_values = NULL;
		loc->nAcode_map = 0;
		loc->allelicVariation = FALSE;
		loc->copyNumberVariation = FALSE;
		loc->integerDosage = FALSE;

		return 1;
	}

	return 0;
}

int locus_set_name(struct locus *loc, const char* value) 
{
	if (loc != NULL && value != NULL) {
		if (loc->name != NULL) {
			free(loc->name);
			loc->name = NULL;
		}
		loc->name = (char*) malloc(strlen(value) + 1);
		if (loc->name != NULL) {
			strcpy(loc->name, value);
			return 1;
		}
	}

	return 0;
}

int locus_free_attributes(struct locus *loc) {
	int i;

	if (loc != NULL) {
		if (loc->name != NULL) {
			free(loc->name);
			loc->name = NULL;
		}
		
		// Free the allele string array.
		if (loc->nAlleles > 0) {
			for (i = 0; i < loc->nAlleles; i++) 
				if (loc->alleles[i] != NULL) free(loc->alleles[i]);

			free(loc->alleles);
			loc->alleles = NULL;
			loc->nAlleles = 0;
		}

		// De-allocate the acode map.
		if (loc->nAcode_map > 0) {
			for (i = 0; i < loc->nAcode_map; i++) {
				if (loc->acode_map_keys[i] != NULL) 
					free(loc->acode_map_keys[i]);
			}
			free(loc->acode_map_keys);
			free(loc->acode_map_values);
			loc->acode_map_keys = NULL;
			loc->acode_map_values = NULL;
			loc->nAcode_map = 0;
		}
		
		return 1;
	}

	return 0;
}

struct locus* locus_create() {
	struct locus *l = (struct locus*) malloc(sizeof(struct locus));
	locus_init(l);

	return l;
}

int locus_set_allele1(struct locus *loc, const char* value) 
{
	if (loc != NULL && value != NULL) {
		strcpy(loc->allele1, value);
		return 1;
	}

	return 0;
}

int locus_set_allele2(struct locus *loc, const char* value) 
{
	if (loc != NULL && value != NULL) {
		strcpy(loc->allele2, value);
		return 1;
	}
	
	return 0;
}

int locus_insert_allele(struct locus *loc, const char* value) {
	if (loc != NULL && value != NULL) {
		if (loc->nAlleles == 0) {
			loc->alleles = (char**) malloc(sizeof(char**));
			*(loc->alleles) = (char*) malloc((sizeof(char) * strlen(value)) + 1);

			if (loc->alleles != NULL && (*loc->alleles) != NULL) {
				strcpy(*(loc->alleles), value);
				loc->nAlleles++;
				return 1;
			} else {
				return 0;
			}

		} else {
			char **pOld = NULL, **pNew = NULL;

			pOld = loc->alleles;
			pNew = (char**) realloc(loc->alleles, (sizeof(char**) * loc->nAlleles) + sizeof(char**));

			if (pNew != NULL) {
				loc->alleles = pNew;
				loc->alleles[loc->nAlleles] = (char*) malloc(strlen(value) + 1);
				strcpy(loc->alleles[loc->nAlleles], value);
				loc->nAlleles++;

				return 1;
			}  else {
				loc->alleles = pOld;
				return 0;
			}
		}
	}

	return 0;
}

int locus_compare(const void* p1, const void* p2) {
	const struct locus **a = (const struct locus **) p1;
	const struct locus **b = (const struct locus **) p2;

	if ((*a)->chr == (*b)->chr) {
		if ((*a)->bp < (*b)->bp) return -1;
		if ((*a)->bp == (*b)->bp) return 0;
		if ((*a)->bp > (*b)->bp) return 1;
	} else if ((*a)->chr < (*b)->chr) 
		return -1;
	else if ((*a)->chr > (*b)->chr) 
		 return 1; 
	
	return 0;
}
